var mxEdgeStyle =
{
	EntityRelation: function(state, source, target, points, result)
	{
		var view = state.view;
		var graph = view.graph;
		var segment =
			mxUtils.getValue(state.style, mxConstants.STYLE_STARTSIZE, mxConstants.ENTITY_SEGMENT) * state.view.scale;
		var isSourceLeft = false;

		if (source != null)
		{
			var sourceGeometry = graph.getCellGeometry(source.cell);

			if (sourceGeometry.relative)
			{
				isSourceLeft = sourceGeometry.x <= 0.5;
			}
			else if (target != null)
			{
				isSourceLeft = target.x + target.width < source.x;
			}
		}
		else
		{
			var tmp = state.absolutePoints[0];

			if (tmp == null)
			{
				return;
			}
			source = new mxCellState();
			source.x = tmp.x;
			source.y = tmp.y;
		}
		var isTargetLeft = true;

		if (target != null)
		{
			var targetGeometry = graph.getCellGeometry(target.cell);

			if (targetGeometry.relative)
			{
				isTargetLeft = targetGeometry.x <= 0.5;
			}
			else if (source != null)
			{
				isTargetLeft = source.x + source.width < target.x;
			}
		}
		else
		{
			var pts = state.absolutePoints;
			var tmp = pts[pts.length - 1];

			if (tmp == null)
			{
				return;
			}
			target = new mxCellState();
			target.x = tmp.x;
			target.y = tmp.y;
		}
		var x0 = (isSourceLeft) ? source.x : source.x + source.width;
		var y0 = view.getRoutingCenterY(source);
		var xe = (isTargetLeft) ? target.x : target.x + target.width;
		var ye = view.getRoutingCenterY(target);
		var seg = segment;
		var dx = (isSourceLeft) ? -seg : seg;
		var dep = new mxPoint(x0 + dx, y0);
		dx = (isTargetLeft) ? -seg : seg;
		var arr = new mxPoint(xe + dx, ye);

		if (isSourceLeft == isTargetLeft)
		{
			var x = (isSourceLeft) ? Math.min(x0, xe) - segment : Math.max(x0, xe) + segment;
			result.push(new mxPoint(x, y0));
			result.push(new mxPoint(x, ye));
		}
		else if ((dep.x < arr.x) == isSourceLeft)
		{
			var midY = y0 + (ye - y0) / 2;
			result.push(dep);
			result.push(new mxPoint(dep.x, midY));
			result.push(new mxPoint(arr.x, midY));
			result.push(arr);
		}
		else
		{
			result.push(dep);
			result.push(arr);
		}
	},
	Loop: function(state, source, target, points, result)
	{
		var view = state.view;
		var graph = view.graph;
		var pt = (points != null && points.length > 0) ? points[0] : null;
		var s = view.scale;

		if (pt != null)
		{
			pt = view.transformControlPoint(state, pt);

			if (mxUtils.contains(source, pt.x, pt.y))
			{
				pt = null;
			}
		}
		var x = 0;
		var dx = 0;
		var y = view.getRoutingCenterY(source);
		var dy = s * graph.gridSize;

		if (pt == null || pt.x < source.x || pt.x > source.x + source.width)
		{
			if (pt != null)
			{
				x = pt.x;
				dy = Math.max(Math.abs(y - pt.y), dy);
			}
			else
			{
				x = source.x + source.width + 2 * dy;
			}
		}
		else if (pt != null)
		{
			x = view.getRoutingCenterX(source);
			dx = Math.max(Math.abs(x - pt.x), dy);
			y = pt.y;
			dy = 0;
		}
		result.push(new mxPoint(x - dx, y - dy));
		result.push(new mxPoint(x + dx, y + dy));
	},
	ElbowConnector: function(state, source, target, points, result)
	{
		var pt = (points != null && points.length > 0) ? points[0] : null;
		var vertical = false;
		var horizontal = false;

		if (source != null && target != null)
		{
			if (pt != null)
			{
				var left = Math.min(source.x, target.x);
				var right = Math.max(source.x + source.width, target.x + target.width);
				var top = Math.min(source.y, target.y);
				var bottom = Math.max(source.y + source.height, target.y + target.height);
				var view = state.view;
				pt = view.transformControlPoint(state, pt);
				vertical = pt.y < top || pt.y > bottom;
				horizontal = pt.x < left || pt.x > right;
			}
			else
			{
				var left = Math.max(source.x, target.x);
				var right = Math.min(source.x + source.width, target.x + target.width);
				vertical = left == right;

				if (!vertical)
				{
					var top = Math.max(source.y, target.y);
					var bottom = Math.min(source.y + source.height, target.y + target.height);
					horizontal = top == bottom;
				}
			}
		}

		if (!horizontal && (vertical || state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL))
		{
			mxEdgeStyle.TopToBottom(state, source, target, points, result);
		}
		else
		{
			mxEdgeStyle.SideToSide(state, source, target, points, result);
		}
	},
	SideToSide: function(state, source, target, points, result)
	{
		var view = state.view;
		var pt = (points != null && points.length > 0) ? points[0] : null;

		if (pt != null)
		{
			pt = view.transformControlPoint(state, pt);
		}

		if (source == null)
		{
			var tmp = state.absolutePoints[0];

			if (tmp == null)
			{
				return;
			}
			source = new mxCellState();
			source.x = tmp.x;
			source.y = tmp.y;
		}

		if (target == null)
		{
			var pts = state.absolutePoints;
			var tmp = pts[pts.length - 1];

			if (tmp == null)
			{
				return;
			}
			target = new mxCellState();
			target.x = tmp.x;
			target.y = tmp.y;
		}
		var l = Math.max(source.x, target.x);
		var r = Math.min(source.x + source.width, target.x + target.width);
		var x = (pt != null) ? pt.x : r + (l - r) / 2;
		var y1 = view.getRoutingCenterY(source);
		var y2 = view.getRoutingCenterY(target);

		if (pt != null)
		{
			if (pt.y >= source.y && pt.y <= source.y + source.height)
			{
				y1 = pt.y;
			}

			if (pt.y >= target.y && pt.y <= target.y + target.height)
			{
				y2 = pt.y;
			}
		}

		if (!mxUtils.contains(target, x, y1) && !mxUtils.contains(source, x, y1))
		{
			result.push(new mxPoint(x, y1));
		}

		if (!mxUtils.contains(target, x, y2) && !mxUtils.contains(source, x, y2))
		{
			result.push(new mxPoint(x, y2));
		}

		if (result.length == 1)
		{
			if (pt != null)
			{
				if (!mxUtils.contains(target, x, pt.y) && !mxUtils.contains(source, x, pt.y))
				{
					result.push(new mxPoint(x, pt.y));
				}
			}
			else
			{
				var t = Math.max(source.y, target.y);
				var b = Math.min(source.y + source.height, target.y + target.height);
				result.push(new mxPoint(x, t + (b - t) / 2));
			}
		}
	},
	TopToBottom: function(state, source, target, points, result)
	{
		var view = state.view;
		var pt = (points != null && points.length > 0) ? points[0] : null;

		if (pt != null)
		{
			pt = view.transformControlPoint(state, pt);
		}

		if (source == null)
		{
			var tmp = state.absolutePoints[0];

			if (tmp == null)
			{
				return;
			}
			source = new mxCellState();
			source.x = tmp.x;
			source.y = tmp.y;
		}

		if (target == null)
		{
			var pts = state.absolutePoints;
			var tmp = pts[pts.length - 1];

			if (tmp == null)
			{
				return;
			}
			target = new mxCellState();
			target.x = tmp.x;
			target.y = tmp.y;
		}
		var t = Math.max(source.y, target.y);
		var b = Math.min(source.y + source.height, target.y + target.height);
		var x = view.getRoutingCenterX(source);

		if (pt != null && pt.x >= source.x && pt.x <= source.x + source.width)
		{
			x = pt.x;
		}
		var y = (pt != null) ? pt.y : b + (t - b) / 2;

		if (!mxUtils.contains(target, x, y) && !mxUtils.contains(source, x, y))
		{
			result.push(new mxPoint(x, y));
		}

		if (pt != null && pt.x >= target.x && pt.x <= target.x + target.width)
		{
			x = pt.x;
		}
		else
		{
			x = view.getRoutingCenterX(target);
		}

		if (!mxUtils.contains(target, x, y) && !mxUtils.contains(source, x, y))
		{
			result.push(new mxPoint(x, y));
		}

		if (result.length == 1)
		{
			if (pt != null && result.length == 1)
			{
				if (!mxUtils.contains(target, pt.x, y) && !mxUtils.contains(source, pt.x, y))
				{
					result.push(new mxPoint(pt.x, y));
				}
			}
			else
			{
				var l = Math.max(source.x, target.x);
				var r = Math.min(source.x + source.width, target.x + target.width);
				result.push(new mxPoint(l + (r - l) / 2, y));
			}
		}
	}
};
var mxStyleRegistry =
{
	values: {},
	putValue: function(name, obj)
	{
		mxStyleRegistry.values[name] = obj;
	},
	getValue: function(name)
	{
		return mxStyleRegistry.values[name];
	},
	getName: function(value)
	{
		for (var key in mxStyleRegistry.values)
		{
			if (mxStyleRegistry.values[key] == value)
			{
				return key;
			}
		}
		return null;
	}
};
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ELBOW, mxEdgeStyle.ElbowConnector);
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ENTITY_RELATION, mxEdgeStyle.EntityRelation);
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_LOOP, mxEdgeStyle.Loop);
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_SIDETOSIDE, mxEdgeStyle.SideToSide);
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_TOPTOBOTTOM, mxEdgeStyle.TopToBottom);
mxStyleRegistry.putValue(mxConstants.PERIMETER_ELLIPSE, mxPerimeter.EllipsePerimeter);
mxStyleRegistry.putValue(mxConstants.PERIMETER_RECTANGLE, mxPerimeter.RectanglePerimeter);
mxStyleRegistry.putValue(mxConstants.PERIMETER_RHOMBUS, mxPerimeter.RhombusPerimeter);
mxStyleRegistry.putValue(mxConstants.PERIMETER_TRIANGLE, mxPerimeter.TrianglePerimeter);